package org.sibframework.sda.reflect;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import org.sibframework.sda.dbmodel.Column;
import org.sibframework.sda.dbmodel.Table;
import org.sibframework.sda.services.ModelNameService;
import org.sibframework.utils.Naming;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;





public class Table2Java {
	Logger logger = LoggerFactory.getLogger(this.getClass());
/*	private static Map<String, Class<?>> TYPE_MAP = new HashMap<String, Class<?>>();
	static {
		TYPE_MAP.put("VARCHAR", String.class);
		TYPE_MAP.put("BIGINT", Long.class);
		TYPE_MAP.put("INT", Integer.class);
		TYPE_MAP.put("DOUBLE", Double.class);
		TYPE_MAP.put("FLOAT", Float.class);
	}*/
	
	private String packag = "";
	private IDBReflect dbr = null;


	public Table2Java(IDBReflect dbr) {
		super();
		this.dbr = dbr;
	}
	public void table2Java(String dir, String packag, String schema) {
		this.packag = packag;
		try {
			List<Table> tables = dbr.showTables(schema);
			Table2Java gener = this;
			StringBuffer sb = new StringBuffer();
			String modelPath = dir + File.separator + packag.replace('.', File.separatorChar) + File.separator;
			String managerPath = modelPath + "manager" + File.separator;
			
			//check manager path
			File managerPathFile = new File(managerPath);
			if (!managerPathFile.exists()) {
				managerPathFile.mkdirs();
			}
			
			//
			for (Table tb : tables) {
				
				//gen model
				Naming classNaming = Naming.createBySqlName(tb.getTableName().toLowerCase());
				String classStream = gener.genModel(classNaming, tb.getDescription());
				String path = modelPath + classNaming.getClassName() + ".java";
				sb.append(classNaming.getClassName()).append('=').append(packag).append('.').append(classNaming.getClassName()).append('\n');
				logger.debug("gen java file: " + path);
				saveFile(classStream, path);
				
				//gen manager
				path = managerPath + classNaming.getClassName() + "Manager.java";
				//跳过已经存在的manager
				if (!new File(path).exists()) {
					classStream = gener.genManager(classNaming);
					logger.debug("gen java file: " + path);
					saveFile(classStream, path);
				}
				
			}
			
			File modelNamesFile = new File(dir + File.separator + ModelNameService.Model_Names_File);
			if (modelNamesFile.exists()) {
				modelNamesFile.delete();
			}
			modelNamesFile.createNewFile();
			PrintWriter pw = new PrintWriter(modelNamesFile);
			pw.print(sb);
			pw.flush();
			pw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	private void saveFile(String classStream, String path) throws IOException,
			FileNotFoundException {
		File javaFile = new File(path);
		if (javaFile.exists()) {
			javaFile.delete();
		}
		javaFile.createNewFile();
		PrintWriter pw = new PrintWriter(javaFile);
		pw.print(classStream);
		pw.flush();
		pw.close();
	}


	private String genManager(Naming classNaming) throws Exception {

		StringBuffer sb = new StringBuffer();

		sb.append("/**\n*").append("Generated by SimpleDataAccess Table2Java engine.").append("\n*/\n");
		
		
		//package
		sb.append("package ").append(this.packag).append(".manager;\n");
		sb.append("\n");
		
		//import
		sb.append("import ").append(this.packag).append(".").append(classNaming.getClassName()).append(";\n");
		sb.append("import java.sql.SQLException;\nimport org.sibframework.sda.manager.ModelManager;\n\n");
	
		String className = classNaming.getClassName() + "Manager";
		sb.append("public class ").append(className).append(" extends ModelManager<" + classNaming.getClassName() + "> {\n");
		sb.append("\n");

		//constructor
		sb.append("\tpublic " + className + "() throws SQLException {\n");
		sb.append("\t\tsuper(" + classNaming.getClassName() + ".class);\n");
		sb.append("\t}\n");
		sb.append("\n}\n");

		return sb.toString();
	}
	
	
	private String genModel(Naming classNaming, String desc) throws Exception {
		
		StringBuffer sb = new StringBuffer();
		
		
		if (desc != null) {
			sb.append("/**\n*").append("Generated by SimpleDataAccess Table2Java engine.").append("\n*/\n");
		}
		
		//package
		sb.append("package ").append(this.packag).append(";\n");
		sb.append("\n");
		
		//desc
		if (desc != null) {
			sb.append("/**\n*").append(desc).append("\n*/\n");
		}
		
		//declare class
		sb.append("public class ").append(classNaming.getClassName()).append(" implements java.io.Serializable {\n");
		sb.append("\n    //Fields Generated\n");
		
		//get fields from table
		//String[][] columns = SimpleDataAccess.getInstance().getColumns(classNaming.getSqlname());
		List<Column> columns = dbr.showColumns(classNaming.getSqlname());
		
		//fields declare.
		for (Column column : columns) {
			String type = Class.forName(TableType2JavaType.map(column)).getName();
			Naming fieldNaming = Naming.createBySqlName(column.getName().toLowerCase());
			
			String comments = this.buildComments(column);
			
			//comments
			if (column.getComments() != null) {
				sb.append(comments);

			}
			
			//field
			sb.append("    private ").append(type).append(" ").append(fieldNaming.getFieldName()).append(" = null;\n");
		}
		
		//getters and setters
		for (Column column : columns) {
			String type = Class.forName(TableType2JavaType.map(column)).getName();
			Naming fieldNaming = Naming.createBySqlName(column.getName().toLowerCase());
			String comments = this.buildComments(column);
		
			sb.append("\n");
			
			//comments
			if (column.getComments() != null) {
				sb.append(comments);
			}
			
			//getter
			sb.append("    public ").append(type).append(" ").append(fieldNaming.getMethodname("get")).append("() {\n");
			sb.append("    \treturn this.").append(fieldNaming.getFieldName()).append(";\n");
			sb.append("    }\n");
			

			//comments
			if (column.getComments() != null) {
				sb.append(comments);
			}
			//setter
			sb.append("    public void ").append(fieldNaming.getMethodname("set")).append("(").append(type).append(" ").append(fieldNaming.getFieldName()).append(") {\n");
			sb.append("    \tthis.").append(fieldNaming.getFieldName()).append(" = ").append(fieldNaming.getFieldName()).append(";\n");
			sb.append("    }\n");
		}
		
		//finish
		sb.append("}");
		
		return sb.toString();
	}
	
	public String buildComments(Column column) {
		StringBuffer sb = new StringBuffer();
		
		//走着
		sb.append("    /**\n     * ");
		
		//数据库注释
		if (column.getComments() != null && column.getComments().length() > 0) {
			sb.append(column.getComments().replaceAll("\n", "<p>\n    *")).append("<p>");
		}


		//能否为空
		sb.append("\n     * Null able: <tt>").append(column.getNullable()).append("</tt>.");
		
		//主键
		if (column.isPrimaryKey()) {
			sb.append("<p>\n     * Primary Key: <tt>").append(column.isPrimaryKey()).append("</tt>.");			
		}

		
		
		//类型
		sb.append("<p>\n     * Type: <tt>").append(column.getType()).append("</tt>.");
		
		//默认值
		if (column.getDefaultValue() != null) {
			sb.append("<\n     * Default: <tt>").append(column.getDefaultValue()).append("</tt>.");
		}
		
		//数据长度
		if (column.getType().equalsIgnoreCase("NUMBER")) {
			sb.append("\n     * Precision: <tt>").append(column.getPrecision()).append("</tt>.");
			sb.append("\n     * Scale: <tt>").append(column.getScale()).append("</tt>.");
		} else {
			sb.append("\n     * Length: <tt>").append(column.getLength()).append("</tt>.");
		}

		//数据库列名
		sb.append("<p>\n     * Column: <tt>").append(column.getName()).append("</tt>.");
		
		//收
		sb.append("<p>\n     */\n");
		return sb.toString();
	}

}
